package com.mi.system.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mi.system.dto.query.RoleQueryDTO;
import com.mi.system.dto.request.RoleRequestDTO;
import com.mi.system.entity.Role;
import com.mi.system.mapper.RoleMapper;
import com.mi.system.vo.RoleVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;

import static com.mi.common.core.constant.enums.RoleEnum.ADMIN;

/**
 * Role service
 *
 * @author jin_huaquan
 * @version 1.0
 * @date 2021/11/1 14:03
 */
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMenuService roleMenuService;
    private final UserRoleService userRoleService;

    @PostConstruct
    public void initRole() {
        boolean exists = existsByRoleCode(ADMIN.getCode());
        if (exists) {
            return;
        }

        Role role = new Role();

        role.setName(ADMIN.getName());
        role.setRoleCode(ADMIN.getCode());
        role.setRemarks(ADMIN.getName());

        baseMapper.insert(role);
    }

    @Override
    public IPage<RoleVO> listRole(Page page, RoleQueryDTO query) {
        return baseMapper.selectByPage(page, query);
    }

    @Override
    public List<RoleVO> listRole(RoleQueryDTO query) {
        return baseMapper.selectByQuery(query);
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean saveRole(RoleRequestDTO request) {
        Assert.isFalse(existsByName(request.getName()), "已存在相同的角色名称");
        Assert.isFalse(existsByRoleCode(request.getRoleCode()), "已存在相同的角色标识");

        Role role = new Role();

        BeanUtil.copyProperties(request, role);

        this.save(role);

        return roleMenuService.saveRoleMenu(request.getMenuIds(), role.getId());
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean updateRole(Long id, RoleRequestDTO request) {
        Role role = baseMapper.selectById(id);
        Assert.notNull(role, "对应角色不存在");

        if (!Objects.equals(request.getName(), role.getName())) {
            Assert.isFalse(existsByName(request.getName()), "已存在相同的角色名称");
        }
        if (!Objects.equals(request.getRoleCode(), role.getRoleCode())) {
            Assert.isFalse(existsByRoleCode(request.getRoleCode()), "已存在相同的角色标识");
        }

        BeanUtil.copyProperties(request, role);

        this.updateById(role);

        return roleMenuService.updateRoleMenu(request.getMenuIds(), role.getId());
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public Role removeRole(Long id) {
        Role role = getById(id);
        Assert.isFalse(Objects.equals(role.getRoleCode(), ADMIN.getCode()), "管理员角色无法删除");
        Assert.isFalse(userRoleService.existUserRole(id), "存在用户绑定该角色，无法删除");

        baseMapper.deleteById(role);

        roleMenuService.removeRoleMenu(id);

        return role;
    }

    /**
     * role name whether exists
     *
     * @param name role name
     * @return result
     */
    private boolean existsByName(String name) {
        return baseMapper.selectCount(Wrappers.<Role>lambdaQuery().eq(Role::getName, name)) > 0;
    }

    /**
     * role code whether exists
     *
     * @param roleCode role code
     * @return result
     */
    private boolean existsByRoleCode(String roleCode) {
        return baseMapper.selectCount(Wrappers.<Role>lambdaQuery().eq(Role::getRoleCode, roleCode)) > 0;
    }
}
